/**
 * @class ErrorResult 错误结果统计模型
 */
const BaseMod = require('./base');
const Platform = require('./platform');
const Channel = require('./channel');
const Version = require('./version');
const ErrorLog = require('./errorLog');
const AppCrashLogs = require('./appCrashLogs');
const SessionLog = require('./sessionLog');
const { DateTime } = require('../lib');
module.exports = class ErrorResult extends BaseMod {
    constructor() {
        super();
        this.tableName = 'error-result';
        this.platforms = [];
        this.channels = [];
        this.versions = [];
        this.errors = [];
    }

    /**
     * 错误结果统计
     * @param {String} type 统计类型 hour：实时统计 day：按天统计，week：按周统计 month：按月统计
     * @param {Date|Time} date 指定日期或时间戳
     * @param {Boolean} reset 是否重置，为ture时会重置该批次数据
     */
    async stat(type, date, reset) {
        //前端js错误统计
        const resJs = await this.statJs(type, date, reset);
        //原生应用崩溃错误统计
        const resCrash = await this.statCrash(type, date, reset);

        return {
            code: 0,
            msg: 'success',
            data: {
                resJs,
                resCrash,
            },
        };
    }

    /**
     * 前端js错误结果统计
     * @param {String} type 统计类型 hour：实时统计 day：按天统计，week：按周统计 month：按月统计
     * @param {Date|Time} date 指定日期或时间戳
     * @param {Boolean} reset 是否重置，为ture时会重置该批次数据
     */
    async statJs(type, date, reset) {
        const allowedType = ['day'];
        if (!allowedType.includes(type)) {
            return {
                code: 1002,
                msg: 'This type is not allowed',
            };
        }
        this.fillType = type;
        const dateTime = new DateTime();
        const dateDimension = dateTime.getTimeDimensionByType(type, -1, date);
        this.startTime = dateDimension.startTime;
        this.endTime = dateDimension.endTime;

        if (this.debug) {
            console.log('dimension time', this.startTime + '--' + this.endTime);
        }

        // 查看当前时间段日志是否已存在,防止重复生成
        if (!reset) {
            const checkRes = await this.getCollection(this.tableName)
                .where({
                    type: 'js',
                    start_time: this.startTime,
                    end_time: this.endTime,
                })
                .get();
            if (checkRes.data.length > 0) {
                console.log('error log have existed');
                return {
                    code: 1003,
                    msg: 'This log have existed',
                };
            }
        } else {
            const delRes = await this.delete(this.tableName, {
                type: 'js',
                start_time: this.startTime,
                end_time: this.endTime,
            });
            console.log('delete old data result:', JSON.stringify(delRes));
        }

        // 数据获取
        this.errorLog = new ErrorLog();
        const statRes = await this.aggregate(this.errorLog.tableName, {
            project: {
                appid: 1,
                version: 1,
                platform: 1,
                channel: 1,
                error_hash: 1,
                create_time: 1,
            },
            match: {
                create_time: {
                    $gte: this.startTime,
                    $lte: this.endTime,
                },
            },
            group: {
                _id: {
                    appid: '$appid',
                    version: '$version',
                    platform: '$platform',
                    channel: '$channel',
                    error_hash: '$error_hash',
                },
                error_count: {
                    $sum: 1,
                },
            },
            sort: {
                error_count: 1,
            },
            getAll: true,
        });

        let res = {
            code: 0,
            msg: 'success',
        };
        if (this.debug) {
            console.log('statRes', JSON.stringify(statRes));
        }
        if (statRes.data.length > 0) {
            this.fillData = [];
            for (const i in statRes.data) {
                await this.fillJs(statRes.data[i]);
            }

            if (this.fillData.length > 0) {
                res = await this.batchInsert(this.tableName, this.fillData);
            }
        }
        return res;
    }

    /**
     * 前端js错误统计结果数据填充
     * @param {Object} data 数据集合
     */
    async fillJs(data) {
        // 平台信息
        let platformInfo = null;
        if (this.platforms && this.platforms[data._id.platform]) {
            //暂存下数据，减少读库
            platformInfo = this.platforms[data._id.platform];
        } else {
            const platform = new Platform();
            platformInfo = await platform.getPlatformAndCreate(data._id.platform, null);
            if (!platformInfo || platformInfo.length === 0) {
                platformInfo._id = '';
            }
            this.platforms[data._id.platform] = platformInfo;
            if (this.debug) {
                console.log('platformInfo', JSON.stringify(platformInfo));
            }
        }

        // 渠道信息
        let channelInfo = null;
        const channelKey = data._id.appid + '_' + platformInfo._id + '_' + data._id.channel;
        if (this.channels && this.channels[channelKey]) {
            channelInfo = this.channels[channelKey];
        } else {
            const channel = new Channel();
            channelInfo = await channel.getChannelAndCreate(data._id.appid, platformInfo._id, data._id.channel);
            if (!channelInfo || channelInfo.length === 0) {
                channelInfo._id = '';
            }
            this.channels[channelKey] = channelInfo;
            if (this.debug) {
                console.log('channelInfo', JSON.stringify(channelInfo));
            }
        }

        // 版本信息
        let versionInfo = null;
        const versionKey = data._id.appid + '_' + data._id.platform + '_' + data._id.version;
        if (this.versions && this.versions[versionKey]) {
            versionInfo = this.versions[versionKey];
        } else {
            const version = new Version();
            versionInfo = await version.getVersionAndCreate(data._id.appid, data._id.platform, data._id.version);
            if (!versionInfo || versionInfo.length === 0) {
                versionInfo._id = '';
            }
            this.versions[versionKey] = versionInfo;
            if (this.debug) {
                console.log('versionInfo', JSON.stringify(versionInfo));
            }
        }

        // 错误信息
        let errorInfo = null;
        if (this.errors && this.errors[data._id.error_hash]) {
            errorInfo = this.errors[data._id.error_hash];
        } else {
            const cacheKey = 'uni-stat-errors-' + data._id.error_hash;
            errorInfo = await this.getCache(cacheKey);
            if (!errorInfo) {
                errorInfo = await this.getCollection(this.errorLog.tableName)
                    .where({
                        error_hash: data._id.error_hash,
                    })
                    .limit(1)
                    .get();
                if (!errorInfo || errorInfo.data.length === 0) {
                    errorInfo.error_msg = '';
                } else {
                    errorInfo = errorInfo.data[0];
                    await this.setCache(cacheKey, errorInfo);
                }
            }
            this.errors[data._id.error_hash] = errorInfo;
        }

        // 最近一次报错时间
        const matchCondition = data._id;
        Object.assign(matchCondition, {
            create_time: {
                $gte: this.startTime,
                $lte: this.endTime,
            },
        });
        const lastErrorLog = await this.getCollection(this.errorLog.tableName)
            .where(matchCondition)
            .orderBy('create_time', 'desc')
            .limit(1)
            .get();
        let lastErrorTime = '';
        if (lastErrorLog && lastErrorLog.data.length > 0) {
            lastErrorTime = lastErrorLog.data[0].create_time;
        }

        //数据填充
        const datetime = new DateTime();
        const insertParams = {
            appid: data._id.appid,
            platform_id: platformInfo._id,
            channel_id: channelInfo._id,
            version_id: versionInfo._id,
            type: 'js',
            hash: data._id.error_hash,
            msg: errorInfo.error_msg,
            count: data.error_count,
            last_time: lastErrorTime,
            dimension: this.fillType,
            stat_date: datetime.getDate('Ymd', this.startTime),
            start_time: this.startTime,
            end_time: this.endTime,
        };

        this.fillData.push(insertParams);

        return insertParams;
    }

    /**
     * 原生应用错误结果统计
     * @param {String} type 统计类型 hour：实时统计 day：按天统计，week：按周统计 month：按月统计
     * @param {Date|Time} date 指定日期或时间戳
     * @param {Boolean} reset 是否重置，为ture时会重置该批次数据
     */
    async statCrash(type, date, reset) {
        const allowedType = ['day'];
        if (!allowedType.includes(type)) {
            return {
                code: 1002,
                msg: 'This type is not allowed',
            };
        }
        this.fillType = type;
        const dateTime = new DateTime();
        const dateDimension = dateTime.getTimeDimensionByType(type, -1, date);
        this.startTime = dateDimension.startTime;
        this.endTime = dateDimension.endTime;

        if (this.debug) {
            console.log('dimension time', this.startTime + '--' + this.endTime);
        }

        // 查看当前时间段日志是否已存在,防止重复生成
        if (!reset) {
            const checkRes = await this.getCollection(this.tableName)
                .where({
                    type: 'crash',
                    start_time: this.startTime,
                    end_time: this.endTime,
                })
                .get();
            if (checkRes.data.length > 0) {
                console.log('error log have existed');
                return {
                    code: 1003,
                    msg: 'This log have existed',
                };
            }
        } else {
            const delRes = await this.delete(this.tableName, {
                type: 'crash',
                start_time: this.startTime,
                end_time: this.endTime,
            });
            console.log('delete old data result:', JSON.stringify(delRes));
        }

        // 数据获取
        this.crashLogs = new AppCrashLogs();
        const statRes = await this.aggregate(this.crashLogs.tableName, {
            project: {
                appid: 1,
                version: 1,
                platform: 1,
                channel: 1,
                create_time: 1,
            },
            match: {
                create_time: {
                    $gte: this.startTime,
                    $lte: this.endTime,
                },
            },
            group: {
                _id: {
                    appid: '$appid',
                    version: '$version',
                    platform: '$platform',
                    channel: '$channel',
                },
                error_count: {
                    $sum: 1,
                },
            },
            sort: {
                error_count: 1,
            },
            getAll: true,
        });

        let res = {
            code: 0,
            msg: 'success',
        };
        if (this.debug) {
            console.log('statRes', JSON.stringify(statRes));
        }
        if (statRes.data.length > 0) {
            this.fillData = [];
            for (const i in statRes.data) {
                await this.fillCrash(statRes.data[i]);
            }

            if (this.fillData.length > 0) {
                res = await this.batchInsert(this.tableName, this.fillData);
            }
        }
        return res;
    }

    async fillCrash(data) {
        // 平台信息
        let platformInfo = null;
        if (this.platforms && this.platforms[data._id.platform]) {
            //暂存下数据，减少读库
            platformInfo = this.platforms[data._id.platform];
        } else {
            const platform = new Platform();
            platformInfo = await platform.getPlatformAndCreate(data._id.platform, null);
            if (!platformInfo || platformInfo.length === 0) {
                platformInfo._id = '';
            }
            this.platforms[data._id.platform] = platformInfo;
            if (this.debug) {
                console.log('platformInfo', JSON.stringify(platformInfo));
            }
        }

        // 渠道信息
        let channelInfo = null;
        data._id.channel = data._id.channel ? data._id.channel : '1001';
        const channelKey = data._id.appid + '_' + platformInfo._id + '_' + data._id.channel;
        if (this.channels && this.channels[channelKey]) {
            channelInfo = this.channels[channelKey];
        } else {
            const channel = new Channel();
            channelInfo = await channel.getChannelAndCreate(data._id.appid, platformInfo._id, data._id.channel);
            if (!channelInfo || channelInfo.length === 0) {
                channelInfo._id = '';
            }
            this.channels[channelKey] = channelInfo;
            if (this.debug) {
                console.log('channelInfo', JSON.stringify(channelInfo));
            }
        }

        // 版本信息
        let versionInfo = null;
        const versionKey = data._id.appid + '_' + data._id.platform + '_' + data._id.version;
        if (this.versions && this.versions[versionKey]) {
            versionInfo = this.versions[versionKey];
        } else {
            const version = new Version();
            versionInfo = await version.getVersionAndCreate(data._id.appid, data._id.platform, data._id.version);
            if (!versionInfo || versionInfo.length === 0) {
                versionInfo._id = '';
            }
            this.versions[versionKey] = versionInfo;
            if (this.debug) {
                console.log('versionInfo', JSON.stringify(versionInfo));
            }
        }

        //app启动次数
        const sessionLog = new SessionLog();
        const sessionTimesRes = await this.getCollection(sessionLog.tableName)
            .where({
                appid: data._id.appid,
                version: data._id.version,
                platform: data._id.platform,
                channel: data._id.channel,
                create_time: {
                    $gte: this.startTime,
                    $lte: this.endTime,
                },
            })
            .count();

        let sessionTimes = 0;
        if (sessionTimesRes && sessionTimesRes.total > 0) {
            sessionTimes = sessionTimesRes.total;
        } else {
            console.log('Not found session logs');
            return false;
        }

        //数据填充
        const datetime = new DateTime();
        const insertParams = {
            appid: data._id.appid,
            platform_id: platformInfo._id,
            channel_id: channelInfo._id,
            version_id: versionInfo._id,
            type: 'crash',
            count: data.error_count,
            app_launch_count: sessionTimes,
            dimension: this.fillType,
            stat_date: datetime.getDate('Ymd', this.startTime),
            start_time: this.startTime,
            end_time: this.endTime,
        };

        this.fillData.push(insertParams);

        return insertParams;
    }
};
